package src.cl.movix.repositories.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

import org.apache.log4j.Logger;

import src.cl.movix.repositories.RepositoryException;

import cl.movix.model.customer.ICustomer;
import cl.movix.model.properties.IProperty;

public class CustomerDAO extends EntityDAO {

	/**
	 * The name of the value for the properties that are for the customers. This
	 * value is meant to be stored at the MODULE column of the PROPERTY table.
	 */
	public static final String CUSTOMER_MODULE = "CUSTOMER";

	/** The Logger for this class */
	private static Logger logger = Logger.getLogger(CustomerDAO.class);

	/**
	 * The super-class constructor.
	 * 
	 * @param connection
	 *            The connection for the super-class.
	 */
	public CustomerDAO(Connection connection) {
		super(connection);
	}

	public void persist(ICustomer customer) throws SQLException,
			RepositoryException {

		/* The customer itself is first persisted */
		this.persistCustomerOnly(customer);

		/* Then, the customer properties */
		this.persistCustomerProperties(customer);
	}

	public void update(ICustomer customer) {
		// TODO Auto-generated method stub

	}

	/**
	 * This method is responsible of creating the user just in the user's table,
	 * without persisting any other customer's field. Additionally, this method
	 * is responsible of updating the customer's id, with the one obtained as
	 * the result of the insertion.
	 * 
	 * @param customer
	 *            The customer to be inserted in the repository.
	 * @return The time elapsed for the SQL transaction.
	 * @throws SQLException
	 *             Thrown if something happens during the insertion.
	 */
	private long persistCustomerOnly(ICustomer customer) throws SQLException {

		/* The SQL Prepared Statement to be executed */
		String INSERT_STMT = "INSERT INTO customers (creation_date) VALUES (?) RETURNING id";

		/* The SQL prepared statement is set */
		PreparedStatement insertStmt;
		try {
			insertStmt = connection.prepareStatement(INSERT_STMT);
			insertStmt.setTimestamp(1, new Timestamp(new Date().getTime()));
		} catch (SQLException e) {
			logger.error("An exception occured when setting the parameters", e);
			throw e;
		}

		/* The initial time is measured */
		long init = System.currentTimeMillis();

		/* The insertion of the record */
		long customerID;
		try {
			insertStmt.execute();
			insertStmt.getResultSet().next();
			customerID = insertStmt.getResultSet().getLong("id");
		} catch (SQLException e) {
			logger.error("An error occurred while inserting the user record", e);
			throw e;
		}

		/* The customer's id is updated */
		customer.setId(customerID);

		/* The final time of the transaction */
		long end = System.currentTimeMillis();

		/* The elapsed time of the transaction is returned */
		return (end - init);

	}

	/**
	 * This method is responsible of persisting the customer's properties.
	 * 
	 * @param customer
	 *            The customer whose properties are to be inserted in the
	 *            repository.
	 * @return The time elapsed for the SQL transaction.
	 * @throws SQLException
	 *             Thrown if something happens during the insertion.
	 * @throws RepositoryException
	 */
	private long persistCustomerProperties(ICustomer customer)
			throws SQLException, RepositoryException {

		long totalTime = 0;

		/* Every customer property is persisted */
		for (IProperty property : customer.getProperties()) {
			totalTime += this.insertCustomerProperty(customer, property);
		}

		/* The elapsed time of the transaction is returned */
		return totalTime;
	}

	/**
	 * This method is responsible of inserting a cusmer property.
	 * 
	 * @param customer
	 *            The customer holding the property.
	 * @param property
	 *            The property to be persisted into the repository.
	 * @return The time that took the persistence action to be performed.
	 * @throws RepositoryException
	 */
	private long insertCustomerProperty(ICustomer customer, IProperty property)
			throws RepositoryException {

		/* A DAO for the property is created */
		PropertyDAO propertyDAO = new PropertyDAO(this.connection);

		long init = System.currentTimeMillis();

		/* The property is persisted */
		try {
			propertyDAO.persist(property, customer);
		} catch (SQLException e) {
			logger.error("Error when inserting the following customer's property: "
					+ property.toString(), e);
		} catch (ClassNotFoundException e) {
			logger.error("The type was not a valid type", e);
			throw new RepositoryException(
					"Error when inserting the following customer's property: "
							+ property.toString());
		}

		/* The final time of the transaction */
		long end = System.currentTimeMillis();

		return (end - init);
	}

}
